<?php

namespace App\Http\Requests;

use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;

class DisposeStoreRequest extends FormRequest
{
    /**
     * @var \App\Project\FieldTranslation\FieldTranslation
     */
    protected $dispose;

    protected $drug;

    /**
     * Prepare the data for validation.
     * @return void
     */
    protected function prepareForValidation()
    {
        $this->dispose = app('field')->get('dispose');
        $this->drug    = app('field')->get('drug');
    }

    public function withValidator(Validator $validator)
    {
        $validator->after(function (Validator $validator) {

            if ($validator->messages()->isEmpty()) {
                $this->inspectionPlanExtend($validator);
                $this->restSchedule($validator);
            }
        });
    }

    /**
     * 生活(作息)规律
     * @param \Illuminate\Validation\Validator $validator
     */
    public function restSchedule(Validator $validator)
    {
        if (\Auth::user()->hospital->isCn()) {
            $rest = $this->input('advise.rest_schedule.accepted');

            if ($rest != 'on') {
                $validator->errors()->add('advise.rest_schedule.accepted', '不能为空');
            }
        }
    }

    //  检查方案拓展项目验证，
    protected function inspectionPlanExtend(Validator $validator)
    {
        $defaultTitles = $this->dispose['inspection_plan'];

        $input = collect($this->input('inspection_plan.extend'));

        if ($input->count()) {
            $input->filter(function ($item) use ($defaultTitles) {
                if (empty($item))
                    return false;

                return in_array($item['title'], $defaultTitles);
            })->map(function ($value, $key) use ($validator) {
                $validator->errors()->add(
                    'inspection_plan.extend.' . $key . '.title',
                    '检查方案中不能添加 ' . $value['title'] . ' 检查'
                );
            });
        }
    }

    /**
     * Determine if the user is authorized to make this request.
     * @return bool
     */
    public function authorize()
    {
        return \Auth::check();
    }

    /**
     * Get the validation rules that apply to the request.
     * @return array
     */
    public function rules()
    {
        return [
            'record_id'                => [
                'required', 'integer', 'min:1',
                Rule::exists('st_medical_records', 'id')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                    $user = \Auth::user();
                    if (!$user->isDoctorsAdmin() && !$user->isAdmin()) {
                        $query->where(['doctor_id' => $user->id]);
                    }
                }),
            ],
            'control_objectives.hba1c' => 'in:' . implode(',', $this->dispose['HbA1c']),
            'control_objectives.fbg'   => 'in:' . implode(',', $this->dispose['FBG']),
            'control_objectives.2hpbg' => 'in:' . implode(',', $this->dispose['2HPBG']),

            'control_objectives.blood_pressure.low'  => [
                'nullable', 'integer', 'min:0'
            ],
            'control_objectives.blood_pressure.high' => [
                'nullable', 'integer', 'min:0'
            ],
            'control_objectives.ldl-c'               => 'nullable|numeric|min:0.01|max:99.99|decimal:2',
            'control_objectives.TG'                  => 'nullable|numeric|min:0.01|max:99.99|decimal:2',
            'control_objectives.TC'                  => 'nullable|numeric|min:0.01|max:99.99|decimal:2',

            //  matters
            'advise.matters.accepted'                => 'accepted',

            'advise.diet.accepted'  => 'accepted',
            'advise.diet.item'      => 'nullable|string|max:50',
            'advise.diet.staple'    => 'nullable|numeric|min:0|max:999|decimal:1',
            'advise.diet.breakfast' => 'nullable|numeric|min:0|max:999|decimal:1',
            'advise.diet.lunch'     => 'nullable|numeric|min:0|max:999|decimal:1',
            'advise.diet.dinner'    => 'nullable|numeric|min:0|max:999|decimal:1',
            'advise.diet.meat'      => 'nullable|numeric|min:0|max:999|decimal:1',

            'advise.low_salt.accepted'              => 'nullable|in:on',
            'advise.low_salt.item'                  => 'nullable|numeric|min:0|max:999|decimal:1',

            //  规律运动 选项
            'advise.regular_exercise.accepted'      => 'accepted',
            'advise.regular_exercise.item'          => 'nullable|string|max:50',
            'advise.regular_exercise.minutes'       => 'nullable|numeric|min:0|max:999',

            //  生活(作息)规律
            //            'advise.rest_schedule.accepted'         => 'accepted',
            //            'advise.rest_schedule.item'             => 'nullable|numeric|min:0|max:999|decimal:1',

            //  SMBG self-monitoring of blood glucose 自我监测血糖
            'advise.smbg.accepted'                  => 'accepted',
            'advise.smbg.items'                     => 'required|array',
            'advise.smbg.items.before_breakfast'    => 'required|in:on',
            'advise.smbg.items.after_breakfast_2'   => 'required|in:on',
            'advise.smbg.items.before_lunch'        => 'nullable|in:on',
            'advise.smbg.items.after_lunch_2'       => 'required|in:on',
            'advise.smbg.items.before_dinner'       => 'nullable|in:on',
            'advise.smbg.items.after_dinner_2'      => 'required|in:on',
            'advise.smbg.items.before_sleep'        => 'nullable|in:on',
            'advise.smbg.items.morning'             => 'nullable|in:on',

            //  治疗暂不变 选项
            'advise.change_treatment_plan.accepted' => 'nullable|in:on',

            //  减重 选项
            'advise.lose_weight.accepted'           => 'nullable|in:on',
            'advise.lose_weight.item'               => 'nullable|string|max:50',

            //  其他
            'advise.take_drugs.accepted'            => 'nullable|in:on',
            'advise.follow_up_clinic.accepted'      => 'nullable|in:on',

            'advise.low_protein.accepted' => 'nullable|in:on',
            'advise.low_fat.accepted'     => 'nullable|in:on',
            'advise.low_purine.accepted'  => 'nullable|in:on',

            //  pec Patient education course 患者教育课程
            'advise.pec.accepted'         => 'nullable|in:on',
            'advise.pec.items'            => 'required_if:pec.accepted,on',
            'advise.pec.items.*'          => 'between:1,11|distinct',
            'advise.pec.other'            => 'nullable|string|max:50',

            'advise.other.treatment'         => 'nullable|in:on',

            //  检查方案
            'inspection_plan.*.accepted'     => 'nullable|in:on',
            'inspection_plan.*.cycle'        => 'integer|between:1,12',
            'inspection_plan.extend.*.title' => 'required_with:inspection_plan.extend|alpha_num|distinct|not_in',
            'inspection_plan.extend.*.cycle' => 'required_with:inspection_plan.extend|integer|between:1,12',

            'schedule.transfer_treatment'             => 'nullable|string',
            'schedule.plan'                           => 'nullable|string',
            'schedule.date'                           => 'nullable|date_format:Y-m-d',
            'medication'                              => 'nullable|array',
            'medication.*.name'                       => [
                'required_with:medication.*',
                Rule::exists('st_drug_dictionary', 'name')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                }),
            ],
            'medication.*.dosage.type'                => 'in:' . implode(',', $this->drug['dosage'][2]['type']),
            'medication.*.dosage.value'               => 'numeric|min:0|max:999|decimal:2',
            'medication.*.dosage.values'              => 'array|min:1|max:4',
            'medication.*.dosage.values.morning'      => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.atnoon'       => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.evening'      => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.before_sleep' => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.unit'                => 'in:' . implode(',', $this->drug['dosage'][2]['unit']),
            'medication.*.start_time'                 => 'date',
            'medication.*.end_time'                   => 'date|after_or_equal:medication.*.start_time',
            'medication.*.usage'                      => 'in:' . implode(',', $this->drug['usage'][2]),
            'medication.*.frequency'                  => 'in:' . implode(',', $this->drug['frequency'][2]),
            'medication.*.remark'                     => 'string|max:50',

            'cn_medication.*.drugs.*.name'   => [
                'string',
                Rule::exists('st_drug_dictionary', 'name')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                }),
            ],
            'cn_medication.*.type'           => 'required|in:1,3',
            'cn_medication.*.drugs.*.weight' => 'required_if:cn_medication.*.type,1|numeric|min:0|max:999',
            'cn_medication.*.usage'          => 'required_if:cn_medication.*.type,1|in:' . implode(',',
                    $this->drug['usage'][1]),
            'cn_medication.*.dosage'         => 'required_if:cn_medication.*.type,1|in:' . implode(',',
                    $this->drug['dosage'][1]['type']),
            'cn_medication.*.frequency'      => 'required_if:cn_medication.*.type,1|in:' . implode(',',
                    $this->drug['frequency'][1]),
            'cn_medication.*.dose'           => 'required_if:cn_medication.*.type,1|integer|min:0|max:999',

            'cn_medication.*.name'               => 'required_if:cn_medication.*.type,3',
            'cn_medication.*.start_time'         => 'nullable|date',
            'cn_medication.*.end_time'           => 'nullable|date',
            'cn_medication.*.times_per_day'      => 'required_if:cn_medication.*.type,3|integer|min:1',
            'cn_medication.*.quantity_per_times' => 'required_if:cn_medication.*.type,3|integer|min:1',
            'cn_medication.*.quantity_unit'      => 'required_if:cn_medication.*.type,3|in:粒,片,袋',
            'cn_medication.*.total'              => 'required_if:cn_medication.*.type,3|integer|min:1',

            'remark' => 'nullable|string|max:255',
        ];
    }

    public function messages()
    {
        return [
            'record_id.required' => '缺少病历ID',
            'record_id.integer'  => '病历ID 必须是整数。',
            'record_id.min'      => '病历ID 必须大于等于 :min。',
            'record_id.exists'   => '病历 不存在或无修改该病历的权限。',

            'control_objectives.hba1c.in'      => 'HbA1c 取值错误。',
            'control_objectives.hba1c.fbg'     => '空腹血糖 取值错误。',
            'control_objectives.hba1c.2hfbg'   => '餐后2h血糖 取值错误。',
            'control_objectives.ldl-c.numeric' => 'LDL-C 必须是一个数字。',
            'control_objectives.ldl-c.min'     => 'LDL-C 必须大于等于 :min',
            'control_objectives.ldl-c.max'     => 'LDL-C 必须小于等于 :max',
            'control_objectives.ldl-c.decimal' => 'LDL-C 最多保留 2位小数',

            '*.*.item.max'     => '补充意见 不能大于 :max个字。',
            'advise.pec.other' => '补充的教育课程 不能大于 :max个字。',

            'inspection_plan.*.cycle.integer'              => '检查周期 值必须是一个数字。',
            'inspection_plan.*.cycle.between'              => '检查周期 值必须介于 :min和 :max之间。',
            'inspection_plan.extend.*.title.required_with' => '检查方案 拓展项 名称必须填写。',
            'inspection_plan.extend.*.title.alpha_num'     => '检查方案 拓展项 名称只能包含字母汉字和数字。',
            'inspection_plan.extend.*.title.distinct'      => '检查方案 拓展项 名称不能重复。',
            'inspection_plan.extend.*.cycle.required_with' => '检查方案 拓展项 的检查周期必须填写。',
            'inspection_plan.extend.*.cycle.integer'       => '检查方案 拓展项 的检查周期必须是一个数字。',
            'inspection_plan.extend.*.cycle.between'       => '检查方案 拓展项 的检查周期必须介于 :min和 :max之间。',

            'schedule.date'                 => 'nullable|date_format:Y-m-d|before_or_equal:now',
            'schedule.date.date_format'     => '转诊日期 格式错误。',
            'schedule.date.before_or_equal' => '转诊日期 格式错误。',

            'medication.*.name.required_with'          => '药物名称 不能为空。',
            'medication.*.name.exists'                 => '药物名称 不存在。',
            'medication.*.dosage.value.required_if'    => '每次剂量的剂量值 不能为空。',
            'medication.*.dosage.value.numeric'        => '剂量值 必须是一个数字。',
            'medication.*.dosage.value.decimal'        => '剂量值 只能保留一位小数。',
            'medication.*.dosage.value.min'            => '剂量值 必须大于等于 :min。',
            'medication.*.dosage.value.max'            => '剂量值 最大 :max。',
            'medication.*.dosage.values.*.required_if' => '分次剂量的剂量值 不能为空。',
            'medication.*.dosage.values.*.numeric'     => '剂量值 必须是一个数字。',
            'medication.*.dosage.values.*.decimal'     => '剂量值 只能保留一位小数。',
            'medication.*.dosage.values.*.min'         => '剂量值 必须大于等于 :min。',
            'medication.*.dosage.values.*.max'         => '剂量值 不能大于 :max。',
            'medication.*.start_time.date'             => '无效的时间值。',
            'medication.*.end_time.date'               => '无效的时间值。',
            'medication.*.end_time.before_or_equal'    => '无效的时间值，时间值不能晚于现在。',
            'medication.*.usage.in'                    => '药品 用法取值错误。',
            'medication.*.frequency.in'                => '药品 使用频次取值错误。',

            'remark.max' => '备注最大 :max 个字符',
        ];
    }
}
